#pragma once
#include "Socket.hpp"
#include <iostream>
#include <sys/poll.h>
class PollServer
{
    const static int gnum = 666;
    const static int gdefaultfd = -1;

public:
    PollServer(uint16_t port) : _port(port), _listensock(make_unique<TcpSocket>())
    {
        _listensock->BuildListenSocket(_port);
    }
    void InitServer()
    {
        fd_array = new struct pollfd[gnum];
        for (int i = 0; i < gnum; i++)
        {
            fd_array[i].fd = gdefaultfd;
        }
        fd_array[0].fd = _listensock->sockfd();
        fd_array[0].events = POLLIN;
    }
    void Accept()
    {
        if ((fd_array[0].revents & POLLIN) == 1)
        {
            // 连接事件就绪
            InetAddr addr;
            int clientfd = _listensock->Accepter(&addr);
            if (clientfd > 0)
            {
                LOG(DEBUG, "get a new link,%d\n", clientfd);
                // 新链接直接放到辅助数组
                // 要让select统一接管
                int flag = 0;
                for (int i = 1; i < gnum; i++)
                {
                    if (fd_array[i].fd == gdefaultfd)
                    {
                        fd_array[i].fd = clientfd;
                        fd_array[i].events = POLLIN | POLLOUT;
                        flag = 1;
                        break;
                    }
                }
                // 没位置了
                if (flag == 0)
                {
                    LOG(WARNING, "server is full\n");
                    ::close(clientfd);
                }
            }
            else
            {
                LOG(ERROR, "accept error\n");
                return;
            }
        }
    }
    void HandlerIO(int i)
    {
        // 读事件就绪
        char buf[1024];
        ssize_t n = ::recv(fd_array[i].fd, buf, sizeof(buf) - 1, 0);
        if (n > 0)
        {
            buf[n] = 0;
            cout << "client:" << buf << endl;
            string echo = "[server echo]:";
            echo += buf;
            ::send(fd_array[i].fd, echo.c_str(), echo.size(), 0); // 此处默认写事件就绪
        }
        else if (n == 0)
        {
            LOG(INFO, "client quit\n");
            ::close(fd_array[i].fd);
            fd_array[i].fd = gdefaultfd;
        }
        else
        {
            LOG(ERROR, "recv,error\n");
        }
    }
    void HandlerEvent()
    {
        // 事件派发
        //  存在大量就绪
        for (int i = 1; i < gnum; i++)
        {
            if (fd_array[i].fd != gdefaultfd)
            {
                // 判断合法且就绪
                if ((fd_array[i].revents & POLLIN) == 1)
                {
                    HandlerIO(i);
                }
            }
        }
        Accept();
    }
    void Loop()
    {
        // 把listensock和accept看做IO类函数，只关心新连接到来
        while (1)
        {
            // 初始化文件描述符集

            int n = ::poll(fd_array, gnum, -1);
            switch (n)
            {
            case 0:
            {
                LOG(DEBUG, "timeout\n");
                break;
            }
            case -1:
            {
                LOG(ERROR, "poll error\n");
                break;
            }
            default:
            {
                LOG(INFO, "haved event ready,n:%d\n", n);
                HandlerEvent();
                PrintList();
                break;
            }
            }
            // sleep(1);
        }
    }
    void PrintList()
    {
        cout << "fd list: ";
        for (int i = 0; i < gnum; i++)
        {
            if (fd_array[i].fd != gdefaultfd)
                cout << fd_array[i].fd << ' ';
        }
        cout << endl;
    }
    ~PollServer()
    {
    }

private:
    uint16_t _port;
    unique_ptr<TcpSocket> _listensock;
    // 为了保证select正常工作，需要借助一个辅助数组，来保存所有合法fd
    struct pollfd *fd_array = nullptr;
};